package com.cloudfunx.common.aop.impl;

import com.alibaba.fastjson.JSON;
import com.cloudfunx.common.aop.Output;
import com.cloudfunx.common.aop.output.OutputFactory;
import com.cloudfunx.common.aop.output.OutputParamInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author linjiayu
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class OutputAspect {

    @Pointcut("@annotation(com.cloudfunx.common.aop.Output)")
    public void check() {
    }

    @Around("check()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        OutputFactory outputFactory = OutputFactory.get();
        Map<String, String> map = null;
        OutputParamInfo info = null;

        if (Objects.nonNull(outputFactory)) {
            map = new HashMap<>();
            info = new OutputParamInfo();
        }

        Object target = pjp.getTarget();
        String clzName = target.getClass().getName();
        log.info("[类名]:{}", clzName);

        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        log.info("[方法名]:{}", method.getName());

        Output annotation = method.getAnnotation(Output.class);
        log.info("[方法注释]:{}", annotation.value());

        Parameter[] parameters = method.getParameters();
        Object[] args = pjp.getArgs();
        if (parameters != null && parameters.length > 0) {
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                Object arg = args[i];
                Annotation requestBody = parameter.getAnnotation(RequestBody.class);
                String v ;
                if (requestBody !=  null ){
                    v = arg == null ? "null": JSON.toJSONString(arg);
                }else{
                    v = arg == null ? "null" : arg.toString();
                }

                log.info("[参数]:{}={}", parameter.getName(), v);

                if (map != null) {
                    map.put(parameter.getName(), v );
                }
            }
        }

        //callback
        if (Objects.nonNull(outputFactory)) {
            info.setClassName(clzName);
            info.setMethodName(method.getName());
            info.setValue(annotation.value());
            info.setParams(map);

            outputFactory.callback(info);
        }

        return pjp.proceed();
    }
}
